home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 1843 / 1843.xpi / content / firebug / tabWatcher.js < prev    next >
Text File  |  2010-01-15  |  26KB  |  832 lines

  1. /* See license.txt for terms of usage */
  2.  
  3. FBL.ns(function() { with (FBL) {
  4.  
  5. // ************************************************************************************************
  6. // Constants
  7.  
  8. const Cc = Components.classes;
  9. const Ci = Components.interfaces;
  10. const nsIWebNavigation = Ci.nsIWebNavigation;
  11. const nsIWebProgressListener = Ci.nsIWebProgressListener;
  12. const nsIWebProgress = Ci.nsIWebProgress;
  13. const nsISupportsWeakReference = Ci.nsISupportsWeakReference;
  14. const nsISupports = Ci.nsISupports;
  15. const nsIURI = Ci.nsIURI;
  16.  
  17. const NOTIFY_STATE_DOCUMENT = nsIWebProgress.NOTIFY_STATE_DOCUMENT;
  18.  
  19. const STATE_IS_WINDOW = nsIWebProgressListener.STATE_IS_WINDOW;
  20. const STATE_IS_DOCUMENT = nsIWebProgressListener.STATE_IS_DOCUMENT;
  21. const STATE_IS_REQUEST = nsIWebProgressListener.STATE_IS_REQUEST;
  22.  
  23. const STATE_START = nsIWebProgressListener.STATE_START;
  24. const STATE_STOP = nsIWebProgressListener.STATE_STOP;
  25. const STATE_TRANSFERRING = nsIWebProgressListener.STATE_TRANSFERRING;
  26.  
  27. const STOP_ALL = nsIWebNavigation.STOP_ALL;
  28.  
  29. const dummyURI = "about:layout-dummy-request";
  30. const aboutBlank = "about:blank";
  31.  
  32. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  33.  
  34. const tabBrowser = $("content");
  35.  
  36. // ************************************************************************************************
  37. // Globals
  38.  
  39. var contexts = [];
  40.  
  41. // ************************************************************************************************
  42.  
  43. top.TabWatcher = extend(new Firebug.Listener(),
  44. {
  45.     // Store contexts where they can be accessed externally
  46.     contexts: contexts,
  47.  
  48.     initialize: function()
  49.     {
  50.         if (Firebug.TraceModule)
  51.             Firebug.TraceModule.addListener(TraceListener);
  52.  
  53.         if (tabBrowser)
  54.             tabBrowser.addProgressListener(TabProgressListener, NOTIFY_STATE_DOCUMENT);
  55.  
  56.         httpObserver.addObserver(TabWatcherHttpObserver, "firebug-http-event", false);
  57.     },
  58.  
  59.     destroy: function()
  60.     {
  61.         this.shuttingDown = true;
  62.  
  63.         httpObserver.removeObserver(TabWatcherHttpObserver, "firebug-http-event");
  64.  
  65.         if (tabBrowser)
  66.         {
  67.             tabBrowser.removeProgressListener(TabProgressListener);
  68.  
  69.             var browsers = Firebug.chrome.getBrowsers();
  70.             for (var i = 0; i < browsers.length; ++i)
  71.             {
  72.                 var browser = browsers[i];
  73.                 this.unwatchTopWindow(browser.contentWindow);
  74.             }
  75.         }
  76.  
  77.         if (Firebug.TraceModule)
  78.             Firebug.TraceModule.removeListener(TraceListener);
  79.     },
  80.  
  81.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  82.  
  83.     /**
  84.      * Called when tabBrowser browsers get a new location OR when we get a explicit user op to open firebug
  85.      * Attaches to a top-level window. Creates context unless we just re-activated on an existing context
  86.      */
  87.     watchTopWindow: function(win, uri, userCommands)
  88.     {
  89.         if (!win)
  90.         {
  91.             return false;
  92.         }
  93.  
  94.         var selectedBrowser = Firebug.chrome.getCurrentBrowser();
  95.         if (selectedBrowser.cancelNextLoad)
  96.         {
  97.             // We need to cancel this load and try again after a delay... this is used
  98.             // mainly to prevent chaos while when the debugger is active when a page
  99.             // is unloaded
  100.             delete selectedBrowser.cancelNextLoad;
  101.             selectedBrowser.webNavigation.stop(STOP_ALL);
  102.             var url = (uri instanceof nsIURI?uri.spec:uri);
  103.             delayBrowserLoad(selectedBrowser, url);
  104.             return;
  105.         }
  106.  
  107.         var context = this.getContextByWindow(win);
  108.         if (context) // then we've looked at this window before in this FF session...
  109.         {
  110.             if (!this.shouldShowContext(context))
  111.             {
  112.                 // ...but now it is not wanted.
  113.                 if (context.browser)
  114.                     delete context.browser.showFirebug;
  115.                 this.unwatchContext(win, context);
  116.  
  117.                 // There shouldn't be context for this window so, remove it from the
  118.                 // global array.
  119.                 remove(contexts, context);
  120.  
  121.                 return;  // did not create a context
  122.             }
  123.             // else we should show
  124.         }
  125.         else // then we've not looked this window in this session
  126.         {
  127.             // decide whether this window will be debugged or not
  128.             var url = (uri instanceof nsIURI) ? uri.spec : uri;
  129.             if (!this.shouldCreateContext(selectedBrowser, url, userCommands))
  130.             {
  131.                 delete selectedBrowser.showFirebug;
  132.                 this.watchContext(win, null);
  133.  
  134.                 return false;  // we did not create a context
  135.             }
  136.  
  137.             var browser = this.getBrowserByWindow(win);
  138.  
  139.             context = this.createContext(win, browser, Firebug.getContextType());
  140.        }
  141.  
  142.         if (win instanceof Ci.nsIDOMWindow && win.parent == win)
  143.         {
  144.             win.addEventListener("pageshow", onLoadWindowContent, onLoadWindowContent.capturing);
  145.             win.addEventListener("DOMContentLoaded", onLoadWindowContent, onLoadWindowContent.capturing);
  146.         }
  147.  
  148.         // Dispatch watchWindow for the outer most DOM window
  149.         this.watchWindow(win, context);
  150.  
  151.         // This is one of two places that loaded is set. The other is in watchLoadedTopWindow
  152.         if (context && !context.loaded)
  153.         {
  154.             context.loaded = !context.browser.webProgress.isLoadingDocument;
  155.  
  156.             // If the loaded flag is set, the proper event should be dispatched.
  157.             if (context.loaded)
  158.                 dispatch(this.fbListeners, "loadedContext", [context]);
  159.  
  160.         }
  161.  
  162.         if (context && !context.loaded && !context.showContextTimeout)
  163.         {
  164.             // still loading, we want to showContext one time but not too agressively
  165.             // xxxHonza: In case where the timeout is fired before the context is actually
  166.             // loaded (i.e. context.loaded == false) and the showContext is called
  167.             // some panels (css, html, dome) are not initialized and remain empty.
  168.             // These panels use if (context.loaded) condidtion to execute the init process.
  169.             // I am increasing the timeout to 2000, I guess that in most cases this shouldn't
  170.             // caus any real delay since showContext should be called through
  171.             // watchLoadedTopWindow and this timeout cancelled.
  172.             context.showContextTimeout = setTimeout(bindFixed( function delayShowContext()
  173.             {
  174.                 if (context.window)   // Sometimes context.window is not defined ?
  175.                     this.rushShowContext(win, context);  // calls showContext
  176.                 else
  177.                 {
  178.                 }
  179.             }, this), 2000);
  180.         }
  181.         else
  182.         {
  183.             this.rushShowContext(win, context);
  184.         }
  185.  
  186.         return context;  // we did create or find a context
  187.     },
  188.  
  189.     rushShowContext: function(win, context)
  190.     {
  191.         if (context.showContextTimeout) // then the timeout even has not run, we'll not need it after all.
  192.             clearTimeout(context.showContextTimeout);
  193.         delete context.showContextTimeout;
  194.  
  195.         // Call showContext only for currently active tab.
  196.         var currentURI = Firebug.chrome.getCurrentURI();
  197.         if (!currentURI || currentURI.spec != context.browser.currentURI.spec)
  198.         {
  199.             return;
  200.         }
  201.  
  202.         this.watchContext(win, context);  // calls showContext
  203.     },
  204.  
  205.     // Listeners decide to show or not
  206.     shouldShowContext: function(context)
  207.     {
  208.         if ( dispatch2(this.fbListeners, "shouldShowContext", [context]))
  209.             return true;
  210.         else
  211.             return false;
  212.     },
  213.  
  214.     // Listeners given force-in and veto on URIs/Window.
  215.  
  216.     shouldCreateContext: function(browser, url, userCommands)
  217.     {
  218.         // called when win has no context, answers the question: create one, true or false?
  219.  
  220.         if (!this.fbListeners)
  221.             return userCommands;
  222.  
  223.         // Create if any listener says true to showCreateContext
  224.         if (dispatch2(this.fbListeners, "shouldCreateContext", [browser, url, userCommands]))
  225.             return true;
  226.  
  227.         if (dispatch2(this.fbListeners, "shouldNotCreateContext", [browser, url, userCommands]))
  228.             return false;
  229.  
  230.         return userCommands;
  231.     },
  232.  
  233.     createContext: function(win, browser, contextType)
  234.     {
  235.         if (contexts.length == 0)
  236.             Firebug.broadcast('enableXULWindow', []);
  237.  
  238.         // If the page is reloaded, store the persisted state from the previous
  239.         // page on the new context
  240.         var persistedState = browser.persistedState;
  241.         delete browser.persistedState;
  242.         var location = safeGetWindowLocation(win).toString();
  243.         //if (!persistedState || persistedState.location != location)
  244.         //    persistedState = null;
  245.  
  246.         // xxxHonza, xxxJJB: web application detection. Based on domain check.
  247.         var prevDomain = persistedState ? getDomain(persistedState.location) : null;
  248.         var domain = getDomain(location);
  249.         if (!persistedState || prevDomain != domain)
  250.             persistedState = null;
  251.  
  252.         // The proper instance of FirebugChrome object (different for detached Firebug and
  253.         // accessible as Firebug.chrome property) must be used for the context object.
  254.         // (the global context object FirebugContext is also different for detached firebug).
  255.         var context = new contextType(win, browser, Firebug.chrome, persistedState);
  256.         contexts.push(context);
  257.  
  258.         context.uid =  FBL.getUniqueId();
  259.  
  260.         browser.showFirebug = true; // this is the only place we should set showFirebug.
  261.  
  262.         dispatch(this.fbListeners, "initContext", [context, persistedState]);
  263.  
  264.         return context;
  265.     },
  266.  
  267.     /**
  268.      * Called once the document within a tab is completely loaded.
  269.      */
  270.     watchLoadedTopWindow: function(win)
  271.     {
  272.         var isSystem = isSystemPage(win);
  273.  
  274.         var context = this.getContextByWindow(win);
  275.         if ((context && !context.window))
  276.         {
  277.             this.unwatchTopWindow(win);
  278.             this.watchContext(win, null, isSystem);
  279.             return;
  280.         }
  281.  
  282.         if (context && !context.loaded)
  283.         {
  284.             context.loaded = true;
  285.  
  286.             dispatch(this.fbListeners, "loadedContext", [context]);
  287.  
  288.             // DOMContentLoaded arrived. Whether or not we did showContext at 400ms, do it now.
  289.             this.rushShowContext(win, context);
  290.         }
  291.     },
  292.  
  293.     /**
  294.      * Attaches to a window that may be either top-level or a frame within the page.
  295.      */
  296.     watchWindow: function(win, context)
  297.     {
  298.         if (!context)
  299.             context = this.getContextByWindow(getRootWindow(win));
  300.  
  301.         var location = safeGetWindowLocation(win);
  302.  
  303.         // Unfortunately, dummy requests that trigger the call to watchWindow
  304.         // are called several times, so we have to avoid dispatching watchWindow
  305.         // more than once
  306.         if (context && context.windows.indexOf(win) == -1 && location != aboutBlank)
  307.         {
  308.             context.windows.push(win);
  309.  
  310.             if (win.parent == win)
  311.             {
  312.                 win.addEventListener("pagehide", onPageHideTopWindow, false);
  313.             }
  314.             else
  315.             {
  316.                 win.addEventListener("unload", onUnloadWindow, false);
  317.             }
  318.  
  319.             dispatch(this.fbListeners, "watchWindow", [context, win]);
  320.  
  321.         }
  322.     },
  323.  
  324.     /**
  325.      * Detaches from a top-level window. Destroys context
  326.      * Called when windows are closed, or user closes firebug
  327.      */
  328.     unwatchTopWindow: function(win)
  329.     {
  330.         var context = this.getContextByWindow(win);
  331.         this.unwatchContext(win, context);
  332.  
  333.         return true; // we might later allow extensions to reject unwatch
  334.     },
  335.  
  336.     /**
  337.      * Detaches from a window, top-level or frame (interior)
  338.      */
  339.     unwatchWindow: function(win)
  340.     {
  341.         var context = this.getContextByWindow(win);
  342.  
  343.         if (!context)
  344.         {
  345.             return;
  346.         }
  347.  
  348.         var index = context.windows.indexOf(win);
  349.         if (index != -1)
  350.         {
  351.             context.windows.splice(index, 1);
  352.             dispatch(this.fbListeners, "unwatchWindow", [context, win]);
  353.         }
  354.     },
  355.  
  356.     /**
  357.      * Attaches to the window inside a browser because of user-activation
  358.      * returns false if no context was created by the attach attempt, eg extension rejected page
  359.      */
  360.     watchBrowser: function(browser)
  361.     {
  362.         registerFrameListener(browser);
  363.  
  364.         var shouldDispatch = this.watchTopWindow(browser.contentWindow, safeGetURI(browser), true);
  365.  
  366.         if (shouldDispatch)
  367.         {
  368.             dispatch(this.fbListeners, "watchBrowser", [browser]);
  369.             return true;
  370.         }
  371.         return false;
  372.     },
  373.  
  374.     /*
  375.      * User closes Firebug
  376.      */
  377.  
  378.     unwatchBrowser: function(browser, userCommands)
  379.     {
  380.         if (!browser)
  381.             return;
  382.  
  383.         delete browser.showFirebug;
  384.  
  385.         var shouldDispatch = this.unwatchTopWindow(browser.contentWindow);
  386.  
  387.         if (shouldDispatch)
  388.         {
  389.             dispatch(this.fbListeners, "unwatchBrowser", [browser, userCommands]);
  390.             return true;
  391.         }
  392.         return false;
  393.     },
  394.  
  395.     watchContext: function(win, context, isSystem)  // called when tabs change in firefox
  396.     {
  397.         if (this.shuttingDown)
  398.             return;
  399.  
  400.         var browser = context ? context.browser : this.getBrowserByWindow(win);
  401.         if (browser)
  402.             browser.isSystemPage = isSystem;
  403.  
  404.         dispatch(this.fbListeners, "showContext", [browser, context]); // context is null if we don't want to debug this browser
  405.     },
  406.  
  407.     unwatchContext: function(win, context)
  408.     {
  409.         if (!context)
  410.         {
  411.             var browser = this.getBrowserByWindow(win);
  412.             if (browser)
  413.             {
  414.                 browser.persistedState = {};
  415.                 delete browser.showFirebug;
  416.                 dispatch(this.fbListeners, "showContext", [browser, null]); // context is null if we don't want to debug this browser
  417.             }
  418.             dispatch(this.fbListeners, "destroyContext", [null, (browser?browser.persistedState:null), browser]);
  419.             return;
  420.         }
  421.  
  422.         var persistedState = {location: context.getWindowLocation()};
  423.         context.browser.persistedState = persistedState;  // store our state on FF browser elt
  424.  
  425.         iterateWindows(context.window, function(win)
  426.         {
  427.             dispatch(TabWatcher.fbListeners, "unwatchWindow", [context, win]);
  428.         });
  429.  
  430.         dispatch(this.fbListeners, "destroyContext", [context, persistedState, context.browser]);
  431.  
  432.         if (this.cancelNextLoad)
  433.         {
  434.             delete this.cancelNextLoad;
  435.             context.browser.cancelNextLoad = true;
  436.         }
  437.  
  438.         context.destroy(persistedState);
  439.         remove(contexts, context);
  440.  
  441.         var currentBrowser = Firebug.chrome.getCurrentBrowser();
  442.         if (!currentBrowser.showFirebug)  // unwatchContext can be called on an unload event after another tab is selected
  443.             dispatch(this.fbListeners, "showContext", [browser, null]); // context is null if we don't want to debug this browser
  444.  
  445.         if (contexts.length == 0)
  446.             Firebug.broadcast("disableXULWindow", []);
  447.     },
  448.  
  449.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  450.  
  451.     getContextByWindow: function(winIn)
  452.     {
  453.         if (!winIn)
  454.             return;
  455.  
  456.         var rootWindow = getRootWindow(winIn);
  457.  
  458.         //if (FBTrace.DBG_INITIALIZE)
  459.         //    FBTrace.sysout("winIn: "+safeGetWindowLocation(winIn).substr(0,50)+" rootWindow: "+safeGetWindowLocation(rootWindow));
  460.  
  461.         if (rootWindow)
  462.         {
  463.             for (var i = 0; i < contexts.length; ++i)
  464.             {
  465.                 var context = contexts[i];
  466.                 if (context.window == rootWindow)
  467.                     return context;
  468.             }
  469.         }
  470.     },
  471.  
  472.     getContextBySandbox: function(sandbox)
  473.     {
  474.         for (var i = 0; i < contexts.length; ++i)
  475.         {
  476.             var context = contexts[i];
  477.             if (context.sandboxes)
  478.             {
  479.                 for (var iframe = 0; iframe < context.sandboxes.length; iframe++)
  480.                 {
  481.                     if (context.sandboxes[iframe] == sandbox)
  482.                         return context;
  483.                 }
  484.             }
  485.         }
  486.         return null;
  487.     },
  488.  
  489.     getBrowserByWindow: function(win)
  490.     {
  491.         var browsers = Firebug.chrome.getBrowsers();
  492.         for (var i = 0; i < browsers.length; ++i)
  493.         {
  494.             var browser = browsers[i];
  495.             if (browser.contentWindow == win)
  496.             {
  497.                 registerFrameListener(browser);
  498.                 return browser;
  499.             }
  500.         }
  501.  
  502.         return null;
  503.     },
  504.  
  505.     iterateContexts: function(fn)
  506.     {
  507.         for (var i = 0; i < contexts.length; ++i)
  508.         {
  509.             var rc = fn(contexts[i]);
  510.             if (rc)
  511.                 return rc;
  512.         }
  513.     },
  514. });
  515.  
  516. // ************************************************************************************************
  517.  
  518. var TabProgressListener = extend(BaseProgressListener,
  519. {
  520.     onLocationChange: function(progress, request, uri)
  521.     {
  522.         // Only watch windows that are their own parent - e.g. not frames
  523.         if (progress.DOMWindow.parent == progress.DOMWindow)
  524.         {
  525.             var srcWindow = getWindowForRequest(request);
  526.             var browser = srcWindow ? TabWatcher.getBrowserByWindow(srcWindow) : null;
  527.             var requestFromFirebuggedWindow = browser && browser.showFirebug;
  528.  
  529.             if (uri && uri.scheme === "wyciwyg")  // document.open() was called, the document was cleared.
  530.                 evictTopWindow(progress.DOMWindow, uri);
  531.  
  532.             if (uri)
  533.                 TabWatcher.watchTopWindow(progress.DOMWindow, uri);
  534.             else // the location change to a non-uri means we need to hide
  535.                 TabWatcher.watchContext(progress.DOMWindow, null, true);
  536.         }
  537.     },
  538.  
  539.     onStateChange: function(progress, request, flag, status)
  540.     {
  541.     }
  542. });
  543.  
  544. // ************************************************************************************************
  545.  
  546. var FrameProgressListener = extend(BaseProgressListener,
  547. {
  548.     onStateChange: function(progress, request, flag, status)
  549.     {
  550.         if (flag & STATE_IS_REQUEST && flag & STATE_START)
  551.         {
  552.             // We need to get the hook in as soon as the new DOMWindow is created, but before
  553.             // it starts executing any scripts in the page.  After lengthy analysis, it seems
  554.             // that the start of these "dummy" requests is the only state that works.
  555.  
  556.             var safeName = safeGetName(request);
  557.             if (safeName && ((safeName == dummyURI) || safeName == "about:document-onload-blocker") )
  558.             {
  559.                 var win = progress.DOMWindow;
  560.                 // Another weird edge case here - when opening a new tab with about:blank,
  561.                 // "unload" is dispatched to the document, but onLocationChange is not called
  562.                 // again, so we have to call watchTopWindow here
  563.  
  564.                 if (win.parent == win && (win.location.href == "about:blank"))
  565.                 {
  566.                     TabWatcher.watchTopWindow(win, win.location.href);
  567.                     return;
  568.                 }
  569.                 else
  570.                     TabWatcher.watchWindow(win);
  571.             }
  572.         }
  573.  
  574.         // Later I discovered that XHTML documents don't dispatch the dummy requests, so this
  575.         // is our best shot here at hooking them.
  576.         if (flag & STATE_IS_DOCUMENT && flag & STATE_TRANSFERRING)
  577.         {
  578.             TabWatcher.watchWindow(progress.DOMWindow);
  579.             return;
  580.         }
  581.  
  582.     }
  583. });
  584.  
  585. // Registers frame listener for specified tab browser.
  586. function registerFrameListener(browser)
  587. {
  588.     if (browser.frameListener)
  589.         return;
  590.  
  591.     browser.frameListener = FrameProgressListener;  // just a mark saying we've registered. TODO remove!
  592.     browser.addProgressListener(FrameProgressListener, NOTIFY_STATE_DOCUMENT);
  593.  
  594. }
  595.  
  596. function getRefererHeader(request)
  597. {
  598.     var http = QI(request, Ci.nsIHttpChannel);
  599.     var referer = null;
  600.     http.visitRequestHeaders({
  601.         visitHeader: function(name, value)
  602.         {
  603.             if (name == 'referer')
  604.                 referer = value;
  605.         }
  606.     });
  607.     return referer;
  608. }
  609.  
  610. var TabWatcherHttpObserver = extend(Object,
  611. {
  612.     // nsIObserver
  613.     observe: function(aSubject, aTopic, aData)
  614.     {
  615.         try
  616.         {
  617.             if (aTopic == "http-on-modify-request")
  618.             {
  619.                 aSubject = aSubject.QueryInterface(Ci.nsIHttpChannel);
  620.                 this.onModifyRequest(aSubject);
  621.             }
  622.         }
  623.         catch (err)
  624.         {
  625.             ERROR(err);
  626.         }
  627.     },
  628.  
  629.     onModifyRequest: function(request)
  630.     {
  631.         var win = getWindowForRequest(request);
  632.         var tabId = Firebug.getTabIdForWindow(win);
  633.  
  634.         // Tab watcher is only interested in tab related requests.
  635.         if (!tabId)
  636.             return;
  637.  
  638.         // Ignore redirects
  639.         if (request.URI.spec != request.originalURI.spec)
  640.             return;
  641.  
  642.         // A document request for the specified tab is here. It can be a top window
  643.         // request (win == win.parent) or embedded iframe request.
  644.         if (request.loadFlags & Ci.nsIHttpChannel.LOAD_DOCUMENT_URI)
  645.         {
  646.             if ( (FBTrace.DBG_ACTIVATION || FBTrace.DBG_WINDOWS) && win == win.parent)
  647.             {
  648.                 FBTrace.sysout("-> tabWatcher TabWatcherHttpObserver *** START *** " +
  649.                     "document request for: " + request.URI.spec + " window for request is "+safeGetWindowLocation(win)+"\n");
  650.             }
  651.  
  652.             if (win == win.parent)
  653.             {
  654.                 // Make sure the frame listener is registered for top level window so,
  655.                 // we can get all onStateChange events and init context for all opened tabs.
  656.                 var browser = TabWatcher.getBrowserByWindow(win);
  657.  
  658.                 if (!browser)
  659.                     return;
  660.  
  661.                 delete browser.FirebugLink;
  662.  
  663.                 if (safeGetWindowLocation(win).toString() == "about:blank") // then this page is opened in new tab or window
  664.                 {
  665.                     var referer = getRefererHeader(request);
  666.                     if (referer)
  667.                     {
  668.                         try
  669.                         {
  670.                             var srcURI = makeURI(referer);
  671.                             browser.FirebugLink = {src: srcURI, dst: request.URI};
  672.                         }
  673.                         catch(e)
  674.                         {
  675.                         }
  676.                     }
  677.                 }
  678.                 else
  679.                 {
  680.                     // Here we know the source of the request is 'win'. For viral activation and web app tracking
  681.                     browser.FirebugLink = {src: browser.currentURI, dst: request.URI};
  682.                 }
  683.             }
  684.         }
  685.     },
  686.  
  687.     QueryInterface : function (aIID)
  688.     {
  689.         if (aIID.equals(Ci.nsIObserver) ||
  690.             aIID.equals(Ci.nsISupportsWeakReference) ||
  691.             aIID.equals(Ci.nsISupports))
  692.         {
  693.             return this;
  694.         }
  695.  
  696.         throw Components.results.NS_NOINTERFACE;
  697.     }
  698. });
  699.  
  700. // ************************************************************************************************
  701. // Local Helpers
  702.  
  703. function onPageHideTopWindow(event)
  704. {
  705.     var win = event.currentTarget;  // we set the handler on a window
  706.     var doc = event.target; // the pagehide is sent to the document.
  707.     if (doc.defaultView != win)
  708.         return; // ignore page hides on interior windows
  709.  
  710.     win.removeEventListener("pagehide", onPageHideTopWindow, false);
  711.  
  712.     // http://developer.mozilla.org/en/docs/Using_Firefox_1.5_caching#pagehide_event
  713.     if (event.persisted) // then the page is cached and there cannot be an unload handler
  714.     {
  715.         //  see Bug 484710 -  add pageIgnore event for pages that are ejected from the bfcache
  716.  
  717.         TabWatcher.unwatchTopWindow(win);
  718.     }
  719.     else
  720.     {
  721.         // Page is not cached, there may be an unload
  722.         win.addEventListener("unload", onUnloadTopWindow, true);
  723.     }
  724. }
  725.  
  726. function evictTopWindow(win, uri)
  727. {
  728.     TabWatcher.unwatchTopWindow(win);
  729. }
  730.  
  731. function onUnloadTopWindow(event)
  732. {
  733.     var win = event.currentTarget;
  734.     win.removeEventListener("unload", onUnloadTopWindow, true);
  735.     TabWatcher.unwatchTopWindow(win);
  736. }
  737.  
  738. function onLoadWindowContent(event)
  739. {
  740.     var win = event.currentTarget;
  741.     try
  742.     {
  743.         win.removeEventListener("pageshow", onLoadWindowContent, onLoadWindowContent.capturing);
  744.     }
  745.     catch (exc)
  746.     {
  747.     }
  748.  
  749.     try
  750.     {
  751.         win.removeEventListener("DOMContentLoaded", onLoadWindowContent, onLoadWindowContent.capturing);
  752.     }
  753.     catch (exc)
  754.     {
  755.     }
  756.  
  757.     // Signal that we got the onLoadWindowContent event. This prevents the FrameProgressListener from sending it.
  758.     var context = TabWatcher.getContextByWindow(win);
  759.     if (context)
  760.         context.onLoadWindowContent = true;
  761.  
  762.     try
  763.     {
  764.         TabWatcher.watchLoadedTopWindow(win);
  765.     }
  766.     catch(exc)
  767.     {
  768.     }
  769.  
  770. }
  771. onLoadWindowContent.capturing = false;
  772.  
  773. function onUnloadWindow(event)
  774. {
  775.     var win = event.currentTarget;
  776.     var eventType = "unload";
  777.     win.removeEventListener(eventType, onUnloadWindow, false);
  778.     TabWatcher.unwatchWindow(win);
  779. }
  780.  
  781. function delayBrowserLoad(browser, uri)
  782. {
  783.     setTimeout(function delayBrowserLoad100()
  784.     {
  785.         browser.loadURI(uri);
  786.     }, 100);
  787. }
  788.  
  789. function safeGetName(request)
  790. {
  791.     try
  792.     {
  793.         return request.name;
  794.     }
  795.     catch (exc)
  796.     {
  797.         return null;
  798.     }
  799. }
  800.  
  801. function safeGetURI(browser)
  802. {
  803.     try
  804.     {
  805.         return browser.currentURI;
  806.     }
  807.     catch (exc)
  808.     {
  809.         return null;
  810.     }
  811. }
  812.  
  813. // ************************************************************************************************
  814.  
  815. var TraceListener =
  816. {
  817.     onDump: function(message)
  818.     {
  819.         var prefix = "->";
  820.         if (message.text.indexOf(prefix) == 0)
  821.         {
  822.             message.text = message.text.substr(prefix.length);
  823.             message.text = trim(message.text);
  824.             message.type = "DBG_WINDOWS";
  825.         }
  826.     }
  827. };
  828.  
  829. // ************************************************************************************************
  830.  
  831. }});
  832.